#include <stdio.h>
#include <stdlib.h>
#include <evalsoc.h>

#define IIC0_BASE_ADDRESS 0x00200400
#define IIC1_BASE_ADDRESS 0x00200500

#define BIT_10_ADDR_master (1<<12)
#define BIT_7_ADDR_master  (0<<12)
#define BIT_10_ADDR_slave  (1<<3)
#define BIT_7_ADDR_slave   (0<<3)

#define IC_RD_REQ   (1 << 5)
#define IC_TX_ABRT  (1 << 6)

#define STANDARD_SPEED 0x2
#define FAST_SPEED     0x4

/**
 * @brief IIC控制器初始化函数-主模式
 * @param base_address IIC模块基地址
 * @param slave_address 从设备地址
 * @param addr_mode 地址模式 (BIT_10_ADDR/BIT_7_ADDR)
 * @param speed_mode 速率模式 (STANDARD_SPEED/FAST_SPEED/HIGH_SPEED)
 * @param apb_freq APB总线频率 (Hz)
 * @param baud_rate 期望IIC总线速率 (Hz)
 */
int iic_init_master(uint32_t base_address,  uint32_t slave_address,uint32_t addr_mode,uint32_t speed_mode,uint32_t apb_freq,uint32_t baud_rate){
    
    dw_iic_regs_t * piic = (dw_iic_regs_t *)base_address;
    uint32_t iic_status;
    int32_t bhz = apb_freq;  // 从参数获取APB时钟
    uint32_t period, lcnt, hcnt;
    uint32_t sda_tx_hold_count, temp;

    /* 禁用IIC控制器 */
    piic->IC_ENABLE = 0;

    /* 配置控制寄存器 */
    iic_status = piic->IC_CON;
    iic_status &= 0x00000063;  // 保持主模式、重启使能等配置
    iic_status = (iic_status & ~0x6) | speed_mode; // 设置速率模式参数
    piic->IC_CON = iic_status;
 

    /* 设置目标设备地址 */
    piic->IC_TAR = slave_address|addr_mode;//主模式下的10bit传输 由TAR 12位决定

    //printf("IC_CON = %08x\n", iic_status);

    /* 计算时序参数 */
    period = (bhz + baud_rate / 2) / baud_rate;
    lcnt = period * 3 / 5;
    hcnt = period - lcnt;
    uint32_t spklen = (lcnt < 16) ? 1 : lcnt / 16;

    /* 配置时钟参数 */
    piic->IC_FS_SCL_HCNT = hcnt;
    piic->IC_FS_SCL_LCNT = lcnt;
    piic->IC_FS_SPKLEN = spklen;

    /* 配置SDA保持时间 */
    sda_tx_hold_count = ((bhz * 3) / 10000000) + 1;
    temp = piic->IC_SDA_HOLD;
    temp = (temp & 0xFFFF0000) | sda_tx_hold_count;
    piic->IC_SDA_HOLD = temp;

    /* 关闭中断并启用控制器 */
    piic->IC_INTR_MASK = 0;
    piic->IC_ENABLE = 1;

    return 0;
}

/**
 * @brief IIC控制器初始化函数-从模式
 * @param base_address IIC模块基地址
 * @param slave_address 自身设备地址
 * @param addr_mode 地址模式 (BIT_10_ADDR/BIT_7_ADDR)
 * @param speed_mode 速率模式 (STANDARD_SPEED/FAST_SPEED/HIGH_SPEED)
 * @param apb_freq APB总线频率 (Hz)
 * @param baud_rate 期望IIC总线速率 (Hz)
 */
int   iic_init_slave(uint32_t base_address,  uint32_t slave_address,uint32_t addr_mode,uint32_t speed_mode,uint32_t apb_freq,uint32_t baud_rate){
    
    dw_iic_regs_t * piic = (dw_iic_regs_t *)base_address;
    uint32_t iic_status;
    int32_t bhz = apb_freq;  // 从参数获取APB时钟
    uint32_t period, lcnt, hcnt;
    uint32_t sda_tx_hold_count, temp;

    /* 禁用IIC控制器 */
    piic->IC_ENABLE = 0;

    /* 配置控制寄存器 */
    iic_status = piic->IC_CON;
    iic_status &= 0x00000022;  // 从模式
    iic_status = (iic_status & ~0x6) | speed_mode; // 设置速率模式参数
    iic_status |= addr_mode;   // 从模式的十位模式由IC_CON的第3位决定
    piic->IC_CON = iic_status;

    //printf("IC_CON = %08x\n", iic_status);

    /* 设置自身设备地址 */
    piic->IC_SAR = slave_address;

    /* 计算时序参数 */
    period = (bhz + baud_rate / 2) / baud_rate;
    lcnt = period * 3 / 5;
    hcnt = period - lcnt;
    uint32_t spklen = (lcnt < 16) ? 1 : lcnt / 16;

    /* 配置时钟参数 */
    piic->IC_FS_SCL_HCNT = hcnt;
    piic->IC_FS_SCL_LCNT = lcnt;
    piic->IC_FS_SPKLEN = spklen;

    /* 配置SDA保持时间 */
    sda_tx_hold_count = ((bhz * 3) / 10000000) + 1;
    temp = piic->IC_SDA_HOLD;
    temp = (temp & 0xFFFF0000) | sda_tx_hold_count;
    piic->IC_SDA_HOLD = temp;

    /* 关闭中断并启用控制器 */
    piic->IC_INTR_MASK = 0;
    piic->IC_ENABLE = 1;

    return 0;
}



/**
 * @brief IIC协议-主模式
 * @param base_address IIC模块的基地址
 * @param slave_address 外设地址
 * @param command 命令
 * @param speed_mode 速率模式 (STANDARD_SPEED/FAST_SPEED/HIGH_SPEED)
 * @return 0
 */
int iic_master( uint32_t base_address,uint32_t slave_address,uint32_t command ,uint32_t speed_mode){

    dw_iic_regs_t * piic = (dw_iic_regs_t *)base_address;
    uint32_t time=0;

    // 定义地址模式变量并初始化
    // uint32_t addr_mode = BIT_7_ADDR_msater;
    uint32_t addr_mode = BIT_10_ADDR_master;


    iic_init_master(base_address, slave_address ,addr_mode, speed_mode, 25000000, 100000);

    if(addr_mode == BIT_10_ADDR_master){
        
        piic->IC_DATA_CMD = 0x100;
        piic->IC_DATA_CMD = 0x100;
        piic->IC_DATA_CMD = 0x100;
        piic->IC_DATA_CMD = 0x300;//stop+read

    }else if(addr_mode == BIT_7_ADDR_master){
        // 读取数据从指定寄存器
        piic->IC_DATA_CMD = 0x100|command; //
        piic->IC_DATA_CMD = 0x100;
        piic->IC_DATA_CMD = 0x100;
        piic->IC_DATA_CMD = 0x300;//stop+read

    }

    // 等待发送完成
    while (1) {
        time = time + 1;
        if (piic->IC_RAW_INTR_STAT & 0x40) {
            break;
        }
        if (piic->IC_TXFLR == 0) {
            break;
        }
        if (time > 1000000) {
            break;
        }
    }

    
    // 读取数据
    while (1) {
        time = time + 1;
        if (piic->IC_RXFLR >= 1) {
            break;
        }
        if (time > 10000000) {
            break;
        }
    }

    while(piic->IC_RXFLR >0){
        uint32_t data = piic->IC_DATA_CMD; // 读取数据
        printf("data = %08lx\n", data);
    }

    printf("IC_STATUS = %08lx\n", piic->IC_STATUS);

    piic->IC_ENABLE = 0; // disable iic
    return 0;

}




/**
 * @brief IIC协议回复函数-从模式
 * @param base_address IIC模块的基地址
 * @param slave_address 从模式自身设备地址
 * @param speed_mode 速率模式 (STANDARD_SPEED/FAST_SPEED/HIGH_SPEED)
 * @return 0
 */
int iic_slave( uint32_t base_address,uint32_t slave_address,uint32_t speed_mode){

    dw_iic_regs_t * piic = (dw_iic_regs_t *)base_address;
    uint32_t status;

    // 定义地址模式变量并初始化
    // uint32_t addr_mode = BIT_7_ADDR_slave;
    uint32_t addr_mode = BIT_10_ADDR_slave;

    uint32_t data[]={0xaa,0xbb,0xcc,0xdd};


    iic_init_slave(base_address, slave_address ,addr_mode, speed_mode, 25000000, 100000);

    while (1){
        // 等待读请求或超时
        while(1) {
            // 轮询中断状态寄存器
            status = piic->IC_RAW_INTR_STAT;
            
            // 处理传输终止
            if(status & IC_TX_ABRT) {
                // 读取清除中断
                piic->IC_CLR_TX_ABRT; 
                // 清空TX FIFO
                while(piic->IC_TXFLR > 0) {
                    (void)piic->IC_CLR_TX_ABRT;
                }
            }
            // 检测读请求
            if(status & IC_RD_REQ) {
                // 清除RD_REQ状态
                piic->IC_CLR_RD_REQ;
                break;
            }

        }

        //printf("IIC1");

        for(int i=0;i<sizeof(data)/sizeof(data[0]);i++) {
            // 等待TX FIFO为空
            while(piic->IC_TXFLR != 0);
            // 写入数据（bit8=0表示数据写入）
            piic->IC_DATA_CMD = data[i];
        }

    }
    //printf("IIC2\n");

    return 0;
}

//iic -MASTER
int dbg_test_iic_maseter( void * parg, int argc, const char * argv[] )
{

    if ( argc < 2 )
	{
		goto usage;
	}
    uint32_t slave_address = strtol(argv[1], NULL, 0); // 从命令行参数中获取从设备地址
    uint32_t register_address = strtol(argv[2], NULL, 0); // 从命令行参数中获取command命令

    printf("slave_address = %08lx\n", slave_address);

    
    iic_master(IIC0_BASE_ADDRESS, slave_address, register_address, STANDARD_SPEED); 

    
    //iic_master(IIC0_BASE_ADDRESS, slave_address, register_address, FAST_SPEED); 


    
    return 0;

usage:
    printf("Usage:mode-master %s <slave_address> <register_address>\n", argv[0]);
    return -1;
}

//iic -SLAVE
int dbg_test_iic_slave( void * parg, int argc, const char * argv[] )
{
    if(argc < 1)
    {
        goto usage;
    }

    uint32_t slave_address = strtol(argv[1], NULL, 0); // 从命令行参数中获取从设备地址

    printf("slave_address = %08lx\n", slave_address);

    iic_slave(IIC0_BASE_ADDRESS,slave_address,STANDARD_SPEED);  // 从命令行参数中定义从设备地址

    return 0;

usage:
    printf("Usage:slaver-address %s\n", argv[0]);
    return -1;
}

